﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PJ.Data.Exception;
using PJ.Framework.Common;
using System.Collections.ObjectModel;
using Microsoft.Practices.EnterpriseLibrary.Caching;

namespace PJ.Data
{
    /// <summary>
    /// ObjectPICProvider : Persist In Cache data provider
    /// </summary>
    /// <typeparam name="I">Object to provide interface type</typeparam>
    /// <typeparam name="C">Object to provide concrete class type</typeparam>
    public abstract class ObjectPICProvider<I, C> : IObjectProvider<I>, IDisposable
        where C : BaseObjectData, I, new()
        where I : class, IObjectData
    {
        private readonly ICacheManager m_Cache;

        private ObservableCollection<C> m_DataObjects;

        protected ObservableCollection<C> DataObjects
        {
            get 
            {
                if (m_DataObjects ==  null)
                {
                    m_DataObjects = m_Cache.GetData(this.GetType().Name) as ObservableCollection<C>;
                    if (m_DataObjects == null)
                        m_DataObjects = new ObservableCollection<C>();
                }
                return m_DataObjects;
            }
        }

        public ObjectPICProvider(ICacheManager cache)
        {
            if (cache == null)
                throw new ArgumentNullException();
            m_Cache = cache;
        }

        protected void Save()
        {
            if (m_DataObjects != null)
                m_Cache.Add(this.GetType().Name, DataObjects);
        }

        public virtual bool Exist(string globalId)
        {
            if (globalId == null)
                throw new ArgumentNullException();
            return (from d in DataObjects where d.GlobalId == globalId select d).Count() > 0;
        }

        public virtual void Delete(string globalId)
        {
            if (globalId == null)
                throw new ArgumentNullException();
            DataObjects.Remove(DataObjects.Where(t => t.GlobalId == globalId).Single());
        }

        public virtual I GetData(string globalId)
        {
            if (globalId == null)
                throw new ArgumentNullException();
            return (from d in DataObjects where d.GlobalId == globalId select d).First();
        }

        public virtual I Find(string globalId)
        {
            if (globalId == null)
                throw new ArgumentNullException();
            return (from d in DataObjects where d.GlobalId == globalId select d).SingleOrDefault();
        }
        public virtual I CachedGet(string globalId)
        {
            return GetData(globalId);
        }

        public virtual I CachedFind(string globalId)
        {
            return Find(globalId);
        }

        private C Set(C entity)
        {
            if (entity == null)
                throw new ArgumentNullException();
            if (string.IsNullOrEmpty(entity.GlobalId))
            {
                entity.GlobalId = Guid.NewGuid().ToString();
                DataObjects.Add(entity);
            }
            else
            {
                if (!DataObjects.Contains(entity))
                {
                    C old = DataObjects.Where(p => p.GlobalId == entity.GlobalId).SingleOrDefault();
                    if (old != null)
                        DataObjects.Remove(old);
                    DataObjects.Add(entity);
                }
            }
            return entity;
        }
        public virtual void Persist(I entity)
        {
            if (entity == null)
                throw new ArgumentNullException();
            C t = entity as C;
            if (t == null)
            {
                t = new C();
                t.Copy(entity);
            }
        }

        public virtual I PersistAndGet(I entity)
        {
            if (entity == null)
                throw new ArgumentNullException();
            C t = entity as C;
            if (t == null)
            {
                t = new C();
                t.Copy(entity);
            }
            return Set(t);
        }

        public virtual void Dispose()
        {
            if (m_DataObjects != null)
                Save();
        }

        public I CreateNewItem()
        {
            return new C();
        }

        #region Interface override
        IObjectData IObjectProvider.CreateNewItem()
        {
            return CreateNewItem();
        }

        IObjectData IObjectProvider.GetData(string globalId)
        {
            return GetData(globalId);
        }

        IObjectData IObjectProvider.Find(string globalId)
        {
            return Find(globalId);
        }

        IObjectData IObjectProvider.CachedGet(string globalId)
        {
            return CachedGet(globalId);
        }

        IObjectData IObjectProvider.CachedFind(string globalId)
        {
            return CachedFind(globalId);
        }

        public virtual IObjectData PersistAndGet(IObjectData data)
        {
            return PersistAndGet((I)data);
        }

        public virtual void Persist (IObjectData data)
        {
            Persist((I)data);
        }

        #endregion

    }
}
